﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Threading;
using System.Runtime.Serialization;
using CHATCLIENT.ServerService;
using ChatInterfaces;
using System.ServiceModel.Channels;
using System.Windows.Forms;
using System.Runtime.Remoting.Messaging;
using CHATCLIENT.TranslatorService;
//using CHATCLIENT.ClientServiceProxy;

namespace CHATCLIENT
{
    public class ClientChat : IChatClient
    {
        public IView View { get; set; }
        private ServerOperationsClient ServOper;
        private string UserName;
        private List<ClientToPass> ClientList;
        private ClientToPass c2p;
        private ServiceHost host;
        private ServerOperationsCallback ServOpCallback;
        private IClientOperationsForClient ClientOperations;
        LanguageServiceClient svc;
        //CHATCLIENT.ClientServiceProxy.ClientOperationsForClientClient icofc;
        private Dictionary<string,CHATCLIENT.ClientServiceProxy.ClientOperationsForClientClient> dicProxyClient;

        public ClientChat() 
        {
            
        }

        public void ClientChat_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (ServOper!=null && ServOper.State != CommunicationState.Closed)
                DoLogout();
        }

        public void DoLogin(string username, string pwd) 
        {
            //Thread.Sleep(5000);
            View.EnableLogin(false);
            this.UserName = username;
            this.dicProxyClient = new Dictionary<string, ClientServiceProxy.ClientOperationsForClientClient>();
            ServOpCallback = new ServerOperationsCallback(HandleNewLogedUser, HandleLogOutUser);
            ServOper = new ServerOperationsClient(new InstanceContext(ServOpCallback));
            ServOper.BeginLogin(username, pwd, LoginCallback, null);
        }

        private void Init()
        {
            // Cria lista que irá guardar os utlizadores que selogarem e que tenham os mesmos interesses
            ClientList = new List<ClientToPass>();

            // inicia  a instacia do serviço que será utlizado pelos outros utlizadores para enviar msgs
            ClientOperations = new ClientService();
            ClientOperations.newMsg += newMsg;  
            host = new ServiceHost(ClientOperations);
            host.Open();
        }

        public void LoginCallback(IAsyncResult ar)
        {
            try
            {
                List<ClientToPass> auxLst = ServOper.EndLogin(ar).ToList();

                Init();

                foreach (ClientToPass cp in auxLst)
                {
                    if (cp.username == UserName)
                        c2p = cp;
                    else
                        ClientList.Add(cp);
                }

                View.RefreshClientList(ClientList);
                View.ApendNewMessage("Logou-se com sucesso");
                View.EnableLogout(true);
                View.EnableControls(true);
            }
            catch (FaultException fc)
            {
                View.EnableLogin(true);
                View.ApendNewMessage(fc.Message);
            }
            catch (Exception ex)
            {
                View.EnableLogin(true);
                View.ApendNewMessage("Serviço não responde " + ex.GetType());
            }
        }

        public void DoLogout()
        {
            //Thread.Sleep(5000);
            View.EnableLogout(false);
            ServOper.BeginLogout(this.UserName, LogoutCallBack, null);
        }

        public void LogoutCallBack(IAsyncResult ar)
        {
            try
            {
                ServOper.EndLogout(ar);
                ServOper.Close();
                host.Close();
                ClientList = null;
                dicProxyClient = null;
                View.RefreshClientList(ClientList);
                View.EnableLogin(true);
                View.EnableControls(false);
                View.ApendNewMessage("LogOut efectuado com sucesso!");
            }
            catch (FaultException fc)
            {
                View.EnableLogout(true);
                View.ApendNewMessage(fc.Message);
            }
            catch (Exception ex)
            {
                View.EnableLogout(true);
                View.ApendNewMessage("Serviço não responde " + ex);
            }
        }

        public void SendPrivateMessage(ClientToPass client, string msg)
        {
            if(svc==null)
                svc = new LanguageServiceClient();

            svc.BeginTranslate("F4E6E0444F32B660BED9908E9744594B53D2E864", msg, c2p.lang, client.lang, "text/html",
                               "general", TranslateCallBack, new CompositeMsg { Msg = msg, Client = client });
        }

        public void TranslateCallBack(IAsyncResult ar)
        {
            try
            {
                string msg = svc.EndTranslate(ar);
                CompositeMsg cmpMsg = (CompositeMsg)ar.AsyncState;

                WSHttpBinding bind = new WSHttpBinding();
                EndpointAddress addr = new EndpointAddress(cmpMsg.Client.BaseAddress);
                CHATCLIENT.ClientServiceProxy.ClientOperationsForClientClient icofc;
                //if (icofc == null)
                if (dicProxyClient.ContainsKey(cmpMsg.Client.username))
                    icofc = dicProxyClient[cmpMsg.Client.username];
                else
                {
                    icofc = new CHATCLIENT.ClientServiceProxy.ClientOperationsForClientClient(bind, addr);
                    dicProxyClient.Add(cmpMsg.Client.username, icofc);
                }

                icofc.BeginSendMessage("<" + c2p.username + "> " + msg, SendMsgCallBack, cmpMsg);
            }
            catch (FaultException fc)
            {
                View.ApendNewMessage("TranslateCallBack" + fc.Message);
            }
            catch (Exception ex)
            {
                View.ApendNewMessage("TranslateCallBack" + ex.Message);
            }
        }

        public void SendMsgCallBack(IAsyncResult ar)
        {
            try
            {
                CompositeMsg cmpMsg = (CompositeMsg)ar.AsyncState;
                dicProxyClient[cmpMsg.Client.username].EndSendMessage(ar);
                //icofc.EndSendMessage(ar);
                //string msg = (string)ar.AsyncState;
                View.ApendNewMessage("<" + this.UserName + "> " + cmpMsg.Msg); 
            }
            catch (FaultException fc)
            {
                View.ApendNewMessage("SendMsgCallBack" + fc.Message);
            }
            catch (Exception ex)
            {
                View.ApendNewMessage("SendMsgCallBack" + ex.Message);
            }
        }

        public void RegistView(IView v)
        {
            View = v;
        }

        // Handler adiciona new user
        public void HandleNewLogedUser(ClientToPass cliente)
        {
            if (ClientList == null)
                ClientList = new List<ClientToPass>();

            ClientList.Add(cliente);
            View.RefreshClientList(ClientList);
            View.ApendNewMessage("<Server> " + cliente.username + " está Online");
        }

        // Handler remove user
        public void HandleLogOutUser(ClientToPass cliente)
        {
            if (ClientList == null)
                return;

            ClientList.Remove(ClientList.SingleOrDefault(d => d.username == cliente.username));
            dicProxyClient.Remove(cliente.username);
            View.RefreshClientList(ClientList);
            View.ApendNewMessage("<Server> " + cliente.username + " Saiu");
        }

        //Handler Nova Mensagem
        public void newMsg(string msg)
        {
            View.ApendNewMessage(msg);
        }
    }

    public class CompositeMsg
    {
        public ClientToPass Client { get; set; }
        public string Msg { get; set; }
    }

}
